package com.mezz.bones.framework.lock.aspect;
import com.mezz.bones.framework.base.domain.enums.ResponseCode;
import com.mezz.bones.framework.base.exception.BaseException;
import com.mezz.bones.framework.lock.annotation.Lock;
import com.mezz.bones.framework.mybatis.helper.TransactionManagerHelper;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

@Aspect
@Component
public class LockAspect {

    @Resource
    private RedissonClient redissonClient;

    @Resource
    private TransactionManagerHelper transactionManagerHelper;

    private final ExpressionParser parser = new SpelExpressionParser();

    @Around("@annotation(lock)")
    public Object around(ProceedingJoinPoint joinPoint, Lock lock) throws Throwable {
        // 解析SpEL表达式
        String lockKey = parseKey(lock.lockKey(), joinPoint);
        String businessKey = parseKey(lock.businessKey(), joinPoint);

        // 合成最终的锁Key
        String finalLockKey = lockKey + ":" + businessKey;

        // 获取过期时间和获取锁的超时时间
        long expire = lock.expire();         // 锁的过期时间，单位毫秒
        long acquireTimeout = lock.acquireTimeout(); // 获取锁的最大等待时间，单位毫秒

        //默认支持可重入锁功能
        RLock rLock = redissonClient.getLock(finalLockKey);

        try {
            // 尝试加锁
            boolean locked = rLock.tryLock(acquireTimeout,expire, TimeUnit.MILLISECONDS);
            if (!locked) {
                throw new BaseException(ResponseCode.TRY_LOCK_ERROR);
            }

            // 事务同步，确保事务提交后才解锁 如当前没有事务则不会有影响
            transactionManagerHelper.registerAfterCompletion(()->{
                // 在事务完成后解锁并清除锁
                if (rLock.isHeldByCurrentThread()) {
                    rLock.unlock();
                }
            });

            return joinPoint.proceed();  // 执行原始方法

        } finally {
            // 如果未注册事务同步或发生其他情况，确保锁被释放
            if (rLock.isHeldByCurrentThread()) {
                rLock.unlock();
            }
        }
    }

    private String parseKey(String key, ProceedingJoinPoint joinPoint) {

        // 如果 key 是空或未包含可能的表达式内容，则直接返回
        if (key == null || !key.contains("#")) {
            return key;
        }

        StandardEvaluationContext context = new StandardEvaluationContext();
        Object[] args = joinPoint.getArgs();
        String[] paramNames = ((org.aspectj.lang.reflect.MethodSignature) joinPoint.getSignature()).getParameterNames();
        for (int i = 0; i < args.length; i++) {
            context.setVariable(paramNames[i], args[i]);
        }
        return parser.parseExpression(key).getValue(context, String.class);
    }
}
